#include "03_mail_box.h"

unsigned pthread_index;

LIST_LINK *end_list = NULL;

MBS *mbs;

MBS *create_mail_box_system()
{
    MBS *temp =(MBS *)malloc(sizeof(MBS));						//申请头节的空间
    if (NULL == temp)
    {
        perror("create_mail_box_system mutex malloc failure\n");
        return NULL;
    }

    int ret = pthread_mutex_init(&temp->mutex, NULL);			//初始化互斥锁
    if (0 != ret)
    {
        perror("create_mail_box_system mutex init failure\n");
        return NULL;
    }

    temp->thread_list = malloc(sizeof(LIST_LINK));				//申请链表头节点空间
    temp->thread_list->next = NULL;
    printf("mail box create ok!! \n");

    return temp;
}

int destroy_mail_box_system(MBS *mbs)
{
    pthread_mutex_destroy(&mbs->mutex);							//销毁互斥锁
    LIST_LINK *temp = NULL;									
    LIST_LINK *find = mbs->thread_list;
    while (find !=  NULL)									//循环销毁线程邮箱的节点
    {
        temp = find;
        find = find->next;
        free(temp);
    }

    free(find);                                                 //释放空间
    return 0;
}

char *get_th_name(MBS *msb)
{
    pthread_t tid = pthread_self();	 						//获取线程本身的tid
    LIST_LINK *find = msb->thread_list;						
    LIST_LINK *end = end_list;
    while (find != end)										//遍历链表
	{
		if (find->elem.tid == tid)							//找到线程邮箱中自己的节点
		{
			break;
		}

        find = find->next;
    }

    if (find->elem.tid == tid)
    {
        return find->elem.name;								//返回找到该线程的名称
    }
    else
	{
        return NULL;
	}
}

int register_to_mail_system(MBS *mbs, char name[], th_fun th)
{
    LIST_LINK *temp =  malloc(sizeof(LIST_LINK));			//申请新的链表节点的空间
    if (NULL == temp)
    {
        perror("register to mail malloc  \n");
        return -1;
    }

    strcpy(temp->elem.name ,name);					//将相应的信息填入节点
    temp->elem.th = th;
    temp->next = NULL;
    init_que(temp);

    pthread_t ret = pthread_create(&(temp->elem.tid), NULL, th, NULL);			//创建线程
    if (0 != ret)
    {
        perror("register to mail thread create\n");
        return -1;
    }

    list_add(mbs->thread_list, temp);        //将节点接入链表
    printf("register mail system  |%s|  ok \n", temp->elem.name);

    return 0;
}

int unregister_from_mailbox(MBS *msb, char *name)
{
    LIST_LINK *find=msb->thread_list->next;
    LIST_LINK *temp = NULL;

    while (NULL != find)						//循环销毁线程邮箱的节点
    {
        temp = find;
        find = find->next;
        if (0 == strcmp(temp->elem.name, name))
        {
            destroy(find);
            free(temp);
            return 0;
        }
    }

    if (0 == strcmp(find->elem.name, name))			//判断循环是正常跳出还是找到了节点跳出
    {
        destroy(find);
        free(find);
        return 0;
    }

    return -1;
}

int wait_all_end(MBS *msb)
{
    LIST_LINK *find=msb->thread_list->next;
    LIST_LINK *end=end_list;
    while (find != end)									    //等待线程邮箱中的线程结束
    {
        pthread_join(find->elem.tid, NULL);
        find = find->next;
    }

    pthread_join(find->elem.tid, NULL);						//为线程邮箱中的现场收尸

    return 0;
}

int send_msg(MBS *msb, char *recvname, DATATYPE data)
{
    MAIL_DATA *temp =  malloc(sizeof(MAIL_DATA));			//创建用于发送数据的结构体

    strcpy(temp->data, data);								//将需要发送的信息复制到刚刚定义的结构体中

    temp->id_of_sender = pthread_self();					//将发送信息线程的tid号写入发送的信息中

    LIST_LINK *find = list_for_each(msb->thread_list, recvname);				//在现场邮箱中寻找与接收线程的消息队列
    if (NULL == find)
    {
        printf("can,t find msg \n");
    }

    char *name = get_th_name(msb);							//获得发送线程的名称
    strcpy(temp->name_of_sender, name);						//将发送和接收线程的名称都写入信息中
    strcpy(temp->name_of_recver, recvname);
    ENTER_CRITICAL_AREA(&msb->mutex); 						//对链表进行上锁
    in_queue(find, temp);									//将信息入队到接收线程的队列中
    QUIT_CRITICAL_AREA(&msb->mutex);						//对链表进行解锁

    return 0;
}

int recv_msg(MBS *msb, char *sendname, DATATYPE data)
{
    MAIL_DATA *temp =  malloc(sizeof(MAIL_DATA));				//创建用于接收数据的结构体
    pthread_t tid =  pthread_self();				//获取线程本身的tid号

    LIST_LINK *find = msb->thread_list;				//定义寻找的指针并将现场邮箱中的头节点指针赋值给该指针

    while (NULL != find)			//在现场邮箱中寻找与该线程的消息队列
    {
        if (find->elem.tid == tid)
		{
            break;
		}

        find = find->next;
    }

    if (find->elem.tid == tid)
    {
        while (1)				//去队列中获取想的信息
        {
            if (find->elem.mail_head != find->elem.mail_tail)			//判断队列是否为空
            {
                ENTER_CRITICAL_AREA(&msb->mutex);						//给链表上锁
                out_queue(find, temp);									//获取数据并且将获取到的数据进行出队操作
                QUIT_CRITICAL_AREA(&msb->mutex);						//给链表解锁
                break;
            }
        }
    }

    strcpy(sendname, temp->name_of_sender);								//获取发送线程的名称
    strcpy(data, temp->data);											//将数据进行复制

    free(temp);															//将申请的空间释放

    return 0;

}
